package xyz.zyl2020.securityjwt.filter;

import io.jsonwebtoken.Claims;
import org.junit.platform.commons.util.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import xyz.zyl2020.securityjwt.utils.JwtUtil;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

import static xyz.zyl2020.securityjwt.utils.JwtUtil.TOKEN_HEADER;

/**
 * @author ZhuYinglong
 * @date 2020/8/31 0031
 */
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

    public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {

        String headerToken = "";
        // 从cookie中获取token
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (JwtUtil.TOKEN_HEADER.equals(cookie.getName()) && StringUtils.isNotBlank(cookie.getValue())) {
                    headerToken = cookie.getValue();
                    break;
                }
            }
        }
        // 从header中获取token
        if (StringUtils.isBlank(headerToken) && StringUtils.isNotBlank(request.getHeader(JwtUtil.TOKEN_HEADER))) {
            headerToken = request.getHeader(JwtUtil.TOKEN_HEADER);
        }
        // 从参数中获取token
        if (StringUtils.isBlank(headerToken) && StringUtils.isNotBlank(request.getParameter(JwtUtil.TOKEN_HEADER))) {
            headerToken = request.getParameter(JwtUtil.TOKEN_HEADER);
        }

        // 校验token头
        if (StringUtils.isBlank(headerToken) || !headerToken.startsWith(JwtUtil.TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }
        // 解析token
        String token = headerToken.substring(JwtUtil.TOKEN_PREFIX.length());
        Claims claims = JwtUtil.parseToken(token);
        // 校验token是否过期
        if (JwtUtil.isExpiration(claims)) {
            chain.doFilter(request, response);
            return;
        }

        String username = JwtUtil.getUsername(claims);
        if (StringUtils.isBlank(username)) {
            chain.doFilter(request, response);
            return;
        }
        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (String authority : JwtUtil.getAuthorities(claims)) {
            authorities.add(new SimpleGrantedAuthority(authority));
        }
        SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(username, null, authorities));

        refreshToken(token, response);
        super.doFilterInternal(request, response, chain);
    }

    /**
     * 刷新token
     *
     * @param token
     * @param response
     */
    private void refreshToken(String token, HttpServletResponse response) {
        token = JwtUtil.refreshToken(token);
        // 将token添加到header中
        response.setHeader(TOKEN_HEADER, JwtUtil.TOKEN_PREFIX + token);
        // 将token添加到cookie中
        Cookie cookie = new Cookie(TOKEN_HEADER, JwtUtil.TOKEN_PREFIX + token);
        cookie.setPath("/");
        cookie.setMaxAge(JwtUtil.TTL_COOKIE);
        response.addCookie(cookie);
    }
}
